import vtk

'''
# FUNCTION TO FILTER EDGES IN THE LATTICE (NOT SURE OF IT YET)
def recursiveConnect(d,e):
	print "rec"
	for f in parents[e]:
		if f in vertex:
			if f not in conns[d]:
				print f
				conns[d].append(f)
				#g.AddGraphEdge(vertex[d],vertex[f])
		else:
			recursiveConnect(d,f)
'''

def write(root,extent,maxlev,ready):
	'''
	print ready
	if root in ready:
		return ""
	else:
		ready.append(root)
	'''
 	if extent[root]["level"] == maxlev:
 		return ""
	tab = ""
	#print root
	for i in range(extent[root]["level"]):
		tab += "\t"
	salida = tab+"<node size=\""+ str(len(extent[root]["objects"])) + "\" name=\""+ctr2(extent[root]["objects"][:5])+"\" >\n"

	for c in extent[root]["children"]:
		salida += write(c,extent,maxlev,ready)
	salida += tab+"</node>\n"
	return salida

def search(p,c,extent):
	if extent[p]["level"] == extent[c]["level"]:
		return False
	if c in extent[p]["children"]:
		return True
	ret = False
	for e in extent[p]["children"]:
		ret = ret and search(e,c,extent)
	return ret


def del_previous(c,e,extent):
	if extent[e]["level"] == 0:
		return False
	for p in extent[e]["parents"]:
		if p in extent[c]["parents"]:
			extent[c]["parents"].remove(p)
			extent[p]["children"].remove(c)
		del_previous(c,p,extent)

def create_lattice_edges(graph,vertex,extent):
	print "Creating Edges..."
	# CREATE EDGES
	conns = {}
	for d in extent:
		if d in vertex:
			conns[d] = []
			for e in extent[d]["children"]:
				#if e not in vertex:	
				#print extent[d]," | ",extent[e]
				#if len(extent[d]) > 0 and len(extent[e]) > 0 and stabs[d] >= staboffset and stabs[e] >= staboffset:
				if e in vertex:
					#if True:
					#if abs(level[d]-level[e]) == 1:
					conns[d].append(e)
					graph.AddGraphEdge(vertex[d],vertex[e])
				#else:
				#	recursiveConnect(d,e)


def create_lattice_vertices(graph,extent,levels,maxlev,staboffset):
	print "Creating Vertices..."
	# ARRAY WITH LABELS TO DISPLAY ON THE GRAPH
	vertex_id_array = vtk.vtkStringArray()
	vertex_id_array.SetName("names")
	vertex_id_array.SetNumberOfTuples(len(extent))

	# ARRAY WITH LABELS TO DISPLAY ON THE GRAPH
	intent_array = vtk.vtkStringArray()
	intent_array.SetName("intent")
	intent_array.SetNumberOfTuples(len(extent))

	# COORDINATES ARRAY
	points = vtk.vtkPoints()
	
	# STABILITY ARRAY
	stab_vertex_array = vtk.vtkFloatArray()
	stab_vertex_array.SetName("stability")
	stab_vertex_array.SetNumberOfTuples(len(extent))
	
	# SUPPORT ARRAY
	sup_vertex_array = vtk.vtkIntArray()
	sup_vertex_array.SetName("support")
	sup_vertex_array.SetNumberOfTuples(len(extent))
	
	vertex = {}

	# MAINTAIN COORDINATES OFFSET INFORMATION 
	indexes = {}
	# CREATE VERTEX
	for e in extent:
		d = extent[e]
		if d["level"] not in indexes:
			indexes[d["level"]] = 1
		if True:
		#if len(d["objects"]) > 0 and d["stability"] >= staboffset:
			# VERTEX
			vertex[e] = graph.AddVertex()
			# CALCULATE COORDINATES
			ylim = 200
			y = ylim-(ylim*d["level"]/maxlev)
			xlim = 200
			x = -1*xlim/2 + xlim * (indexes[d["level"]])/(len(levels[d["level"]])+1)		
				
			#ASSIGN VALUES
			points.InsertNextPoint(x,y,0.0)
			#print str(d["level"])+"-\n"+ctr(d["objects"])+"\nx\n"+str(e)
			vertex_id_array.SetValue(vertex[e],str(len(d["objects"]))+"-\n"+ctr(d["objects"][:5])+"\nx\n"+str(e))#+"   "+str(x)+","+str(y))
			intent_array.SetValue(vertex[e],e)
			stab_vertex_array.SetValue(vertex[e],d["stability"])
			sup_vertex_array.SetValue(vertex[e],len(d["objects"]))
		indexes[d["level"]] += 1
	return vertex, points, vertex_id_array,stab_vertex_array,sup_vertex_array,intent_array



'''
Clean the lattice concepts' objects recursively:
Given two concepts X = (A,B), Y = (C,D) and X <= Y meaning that C is a subset of A 
this algorithm cleans the intesection of C and A.
'''
def clean(e,forclean,besides,extent):
	if extent[e]["level"] <= 1:
		return ['']
	for p in extent[e]["parents"]:
		newfc = []
		for con in forclean:
			if con in extent[p]["objects"]:
				extent[p]["objects"].remove(con)
		for con in besides:
			if con in extent[p]["objects"]:
				extent[p]["objects"].remove(con)
				newfc.append(con)
		for con in extent[p]["objects"]:
			newfc.append(con)
		#arrow = str(extent[d]["level"])
		#for i in range(extent[d]["level"]-1):
		#	arrow += "-"
		#print arrow+">"+str(extent[p]["objects"][:5])
		clean(p,forclean,newfc,extent)

'''
Reads a lattice from Coron output.
'''
def readLattice(lattice):
	f = open(lattice, "r")
	__lineN = 3
	counter = 0
	extent={}
	stabs = {}
	parents={}
	level={}
	levels={}
	maxlev = 0
	for line in f:
		if not (line.startswith("#") or line.startswith("Top") or line.startswith("Bottom") or line.startswith("\n") or "generators" in line):
			counter += 1
			if counter%__lineN==1: # Info intent extent
				# Intent
				intent = line[line.index("{")+1:line.index("}")]
	 			#print intent
				if intent != "":
					# Extent
					extent[intent] = {}
					extent[intent]["objects"] = line[line.index("[")+1:line.index("]")].split(", ")
					#print extent[intent]
					# Level
					lev = line[line.index("level=")+6:line.index("stability")].replace(", ","")
					stab = line[line.rfind("=")+1:]
					stab = float(stab.replace("]\n",""))
					extent[intent]["stability"] = stab
					lev = int(lev)
					extent[intent]["level"] = lev
					if lev > maxlev:
						maxlev = lev
					if lev not in levels:
						levels[lev] = []
					levels[lev].append(intent)
				else:
					intent = "none"
					extent[intent] = {}
					extent[intent]["objects"] = ["ALL"]
					extent[intent]["level"] = 0
					extent[intent]["stability"] = 1.0
					levels[0] = [intent]
			if counter%__lineN==2: # Information of parents
				#if intent == "none":
				#	parents[intent] = []
				#else:
				if True:
					parents[intent] = []
					extent[intent]["parents"] = []
					parent = line[line.index("[")+1:line.index("]")]
					parent = parent.split("}, ")
					for c in range(len(parent)):
						par = parent[c].replace("{","").replace("}","").strip()
						if par == "":
							extent[intent]["parents"].append("none")
						else:
							extent[intent]["parents"].append(par)
			if counter%__lineN==0: # Information of parents
				#if intent == "none":
				#	parents[intent] = []
				#else:
				if True:
					parents[intent] = []
					extent[intent]["children"] = []
					parent = line[line.index("[")+1:line.index("]")]
					parent = parent.split("}, ")
					for c in range(len(parent)):
						par = parent[c].replace("{","").replace("}","").strip()
						if par == "":
							extent[intent]["children"].append("none")
						else:
							extent[intent]["children"].append(par)
	return [extent,levels,maxlev]

def getTopX(extent, X):
	stabs = {}
	for e in extent:
		d = str(extent[e]["stability"])+"-"+str(extent[e]["objects"])
		stabs[d] = e
	keys = stabs.keys()
	keys.sort(reverse=True)
	if len(keys) < X:
		limit = len(keys)
	else:
		limit = X
	intents = {}
	for i in range(limit):
		intent = extent[stabs[keys[i]]]["objects"]
		intent.sort()
		intents[str(intent)] = stabs[keys[i]]
	#print "\n\n\n*******************"
	#for i in intents:
	#	print i + str(extent[intents[i]]["stability"])
	return intents


# FORMATING FUNCTION (USELESS)
def ctr(ar):
	st = ""
	for i in ar:
		st+=i+"\n"
	return st
	
	# FORMATING FUNCTION (USELESS)
def ctr2(ar):
	st = ""
	for i in ar:
		st+=i+", "
	return st


